"""
本代码用于模拟多种并发编程在工程中的实际应用
* ThreadPoolExecutor
* ProcessPoolExecutor
* ...
"""
from time import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed


import asyncio
from functools import partial

import time
def timer(func):
    """
    计时装饰器
    A decorator that prints the time it takes to execute a function.
    :param func:需要装饰的函数
    :return:函数结果
    """

    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.8f} seconds to execute.")
        return result

    return wrapper


class DataProcess:
    def __init__(self):
        # 为该给初始化 '并行' 池子
        self.thread_executor = ThreadPoolExecutor(max_workers=10)
        self.process_executor = ProcessPoolExecutor(max_workers=10)

    @staticmethod
    async def heavy_compute(num: int = 10000000):
        """
        一个耗时任务
        执行一次约 1.06003451秒
        :param num:
        :return:
        """
        res = sum([i * i for i in range(num)])
        print(f"num = {num} ,res = {res}")
        return res

    @staticmethod
    async def heavy_compute_list(content: str):
        """
        一个耗时任务
        执行一次约 1.06003451秒
        :param l1:
        :return:
        """
        print(f"content: {content}")
        print("睡眠3秒")
        await asyncio.sleep(3)

    @timer
    async def heavy_compute_sync(self, loop_num=10):
        """
        一个串行函数
        执行完约 10.47303486s
        :param loop_num:
        :return:
        """
        for _ in range(loop_num):
            self.heavy_compute()

    @timer
    def heavy_compute_thread(self, loop_num: int = 10):
        futures = []
        res = []
        for _ in range(loop_num):
            future = self.thread_executor.submit(self.heavy_compute)
            futures.append(future)
        for f in as_completed(futures):
            fr = f.result()
            res.append(fr)
        print(f"多线程, res : {res}")

    @timer
    def heavy_compute_process(self, loop_num: int = 10):
        """
        因为 heavy_computes是一个重度计算任务，所以多核心一起算有加速效果
        time:
        :param loop_num:
        :return:
        """
        futures = []
        res = []
        for _ in range(loop_num):
            future = self.process_executor.submit(self.heavy_compute)
            futures.append(future)
        for f in as_completed(futures):
            fr = f.result()
            res.append(fr)
        print(f"多线程, res : {res}")

    async def process_async(self, func=None):
        future = self.process_executor.submit(func)
        res = future.result()
        print(f"process_async res : {res}")
        return res

    @timer
    async def batch_process_async(self, loop_num: int = 10):
        # loop = asyncio.get_running_loop()
        # mr = await loop.run_in_executor(self.process_executor, partial(self.heavy_compute_list, content='jarvis'))
        mr = await self.heavy_compute_list(content='jarvis')
        print(f"mr:{mr}")


def func_time_test():
    dp = DataProcess()
    # time = 1.06003451秒
    # dp.heavy_compute()

    # time = 10.47303486s
    # dp.heavy_compute_sync()

    # time=10.98426175s 没有加速效果，以为是中计算任务，线程应该用于io等等待任务
    # dp.heavy_compute_thread()

    # time=3.72347641 有加速效果，适合多核心工作
    # 这种写法适用于已经知道本次并行一共需要处理哪些任务，就可以进行数据切分，然后并行开始
    # dp.heavy_compute_process()

    # 如果不知道全部的任务，用于用户的请求呢？可以使用下面的方案
    asyncio.run(dp.batch_process_async())


if __name__ == '__main__':
    func_time_test()
